package edu.hawaii.halealohacli.kmj;

import org.wattdepot.resource.source.jaxb.Source;
import java.util.TreeMap;
import java.util.Map.Entry;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;

/**
 * Command that takes two dates as input, and prints the Hale Aloha towers ranked in
 * over of increasing energy consumption over that time period.
 * 
 * @author Micah Takabayashi
 */
public class RankTowers implements Command {

  private XMLGregorianCalendar start;
  private XMLGregorianCalendar end;
  private WattDepotClient client;
  
  /**
   * Constructor.
   * @param client WattDepot client to use.
   * @param start Interval start time. Only day, month, and year values will be used.
   * @param end Interval end time. Only day, month, and year values will be used. Should be
   * more recent than start.
   */
  public RankTowers(WattDepotClient client, XMLGregorianCalendar start, XMLGregorianCalendar end) {
    this.start = start;
    this.end = end;
    this.client = client;
  }
  
  /**
   * Queries WattDepot client for data on Hale Aloha towers, ranks towers by energy consumption
   * over the requested period, and then prints the results to command line. Prints an error
   * if there is any problem.
   */
  @Override
  public void printResult() {
    
    // Check to make sure a connection can be made. 
    if (! client.isHealthy()) {
      System.out.println("Error: Could not connect to server using client.");
      return;
    }
    
    // Attempts to acquire a list of sources.
    Source[] sources = this.getSources();
    if (sources == null) {
      return;
    }
    
    // Checks each of the towers for their energy consumption and inserts into a TreeList.
    TreeMap<Integer, String> sortedSources = new TreeMap<Integer, String>();
    for (Source source : sources) {
      sortedSources.put(this.getEnergy(source, this.start, this.end), source.getName());
    }
    
    // Prints the list of sources sorted by their energy consumption.
    System.out.println(this.getIntervalString());
    Entry<Integer, String> currentEntry = sortedSources.pollFirstEntry();
    while (currentEntry != null) {
      System.out.format("%-20s %d kWh%n", currentEntry.getValue(), currentEntry.getKey() / 1000);
      currentEntry = sortedSources.pollFirstEntry();
    }
    
  }
  
  /**
   * Retrieves the energy consumed by a source between object's start and end times.
   * @param source Source to query.
   * @param start Start time of interval.
   * @param end End time of interval.
   * @return Energy consumed between this instance's start and end times.
   */
  public int getEnergy(Source source, XMLGregorianCalendar start, XMLGregorianCalendar end) {
    int energy = 0;
    try {
      energy = (int)client.getEnergyConsumed(source.getName(), start, end, 0);
    }
    catch (Exception e) {
      System.out.println("Error: Unable to query sources for energy consumption.");
    }
    
    return energy;
  }
  
  /**
   * Retrieves an array of four sources, each representing one of the four Hale Aloha towers. 
   * @return Sources for each of the Hale Aloha towers, or null if there is an error.
   */
  public Source[] getSources() {
    Source[] sources = new Source[4];
    String errorMessage = "Error: Unable to acquire one or more sources from server.";
    
    try {
      sources[0] = client.getSource("Mokihana");
      sources[1] = client.getSource("Ilima");
      sources[2] = client.getSource("Lehua");
      sources[3] = client.getSource("Lokelani");
    }
    catch (NotAuthorizedException e) {
      System.out.println(errorMessage);
      return null;
    }
    catch (ResourceNotFoundException e) {
      System.out.println(errorMessage);
      return null;
    }
    catch (BadXmlException e) {
      System.out.println(errorMessage);
      return null;
    }
    catch (MiscClientException e) {
      System.out.println(errorMessage);
      return null;
    }
  
    return sources;
  }
  
  /**
   * Constructs and returns a string showing information about the queried time interval.
   * To be printed before the actual tower energy consumption information.
   * @return String with information about the time interval.
   */
  private String getIntervalString() {
    
    String result = "";
    
    String start = Integer.toString(this.start.getYear());
    start += "-" + Integer.toString(this.start.getMonth());
    start += "-" + Integer.toString(this.start.getDay());
    
    String end = Integer.toString(this.end.getYear());
    end += "-" + Integer.toString(this.end.getMonth());
    end += "-" + Integer.toString(this.end.getDay());
    
    result += "For the interval " + start + " to " + end + ", energy consumption by tower was:";
    return result;
  }

}



